﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Web;
using log4net;
using System.Reflection;
using System.Text;
using System.Xml.XPath;
using System.IO;
using System.Text.RegularExpressions;

namespace GrailTechnology.AutoTags.Providers
{
    [Serializable]
    public class OpenCalaisService : ITagProvider
    {

        private static readonly ILog Log_ = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        private const string Uri = "http://api.opencalais.com/enlighten/calais.asmx/Enlighten";

        #region Private Fields
        private readonly string _licence;
        private const string Parameters =
@"&lt;c:params xmlns:c=""http://s.opencalais.com/1/pred/"" xmlns:rdf=""http://www.w3.org/1999/02/22-rdf-syntax-ns#""&gt;&lt;c:processingDirectives c:allowDistribution=""true"" c:enableMetaDataType=""GenericRelations,SocialTags"" c:allowSearch=""true"" c:contentType=""text/txt"" c:outputFormat=""Text/Simple""&gt;&lt;/c:processingDirectives&gt;&lt;c:externalMetadata&gt;&lt;/c:externalMetadata&gt;&lt;/c:params&gt;";

        #endregion

        public OpenCalaisService()
        {
            _licence = Config.Instance.OpenCalaisApiKey;
            if (string.IsNullOrEmpty(_licence))
            {
                Log_.Error("AutoTags - AutoTags.APIKey not found in web.config");
                throw new Exception("Missing API key. Add your OpenCalais licence key to the autotags.config");
            }
       
        }

        public WebProxy Proxy
        {
            get;
            set;
        }

        public string[] GenerateTags(string content)
        {
            try
            {
                var client = new WebClient();
                client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

                if (Proxy != null)
                {
                    client.Proxy = Proxy;
                }

                string sendParams = string.Format("licenseID={0}&content={1}&paramsXML={2}", _licence,
                                       HttpUtility.UrlEncode(content), HttpUtility.HtmlDecode(Parameters));
                // log.Debug("Requesting: " + sendParams);

                byte[] byteArray = Encoding.UTF8.GetBytes(sendParams);
                byte[] responseArray = client.UploadData(Uri, "POST", byteArray);

                // _errors.Clear();
                string[] result = ResponseToList(Encoding.ASCII.GetString(responseArray)).ToArray();
                Log_.Debug("Tags: " + string.Join(", ", result));
                return result;

            }
            catch (Exception ex)
            {
                Log_.Fatal(ex);
                throw;
            }
        }

        private List<string> ResponseToList(string text)
        {
            var tags = new List<string>();
            var doc = new XPathDocument(new StringReader(Decode(text)));

            var navigator = ((IXPathNavigable)doc).CreateNavigator();
            XPathNodeIterator nodes = navigator.Select("//*");

            while (nodes.MoveNext())
            {
                if (nodes.Current.Name == "CalaisSimpleOutputFormat")
                {
                    XPathNodeIterator newIter = nodes.Current.SelectDescendants(XPathNodeType.Element, false);
                    while (newIter.MoveNext())
                    {
                        AnalyseString(tags, newIter.Current.Name, newIter.Current.Value);
                    }
                    break;
                }
            }

            return tags;
        }

        private void AnalyseString(List<string> list, string name, string value)
        {
            Log_.Debug("Calais tag: " + value);

            if (name != "Topics")
            {
                if (!IsUrl(value))
                {
                    if (name == "Company")
                    {
                        list.Add(value.Replace("_", " "));
                    }
                    else
                    {
                        list.AddRange(value.Split('_'));
                    }
                }
            }
        }

        public bool IsUrl(string tag)
        {
            var match = Regex.Match(tag, @"^(http:\/\/|https:\/\/|ftp:\/\/)");
            return match.Success;
        }

        private string Decode(string encoded)
        {
            return HttpUtility.UrlDecode(encoded).Replace("&lt;", "<").Replace("&gt;", ">");
        }

    }
}